#include "stdafx.h"
#include "ui_control.h"
#include "ui_focusable_control.h"

_SSL_BEGIN
_SSUIL_BEGIN

struct UIFindControlByName
{
	tstring name;
};

UIControl::UIControl()
{
	// preset_pos_;
	auto_width_by_ = kASByAuto;
	auto_height_by_ = kASByAuto;
	v_preset_layout_type_ = kLPCenter;
	h_preset_layout_type_ = kLPCenter;
	// client_borders_;
	// pos_;
	childs_position_has_relation_ = false;
	background_color_ = 0x666666;
	disabled_background_color_ = 0x999999;
	properties_ = 0;
	// tooltip_info_;
	background_transparent_ = false;
	border_color_ = 0;
	show_border_ = true;
	// background_image_
	// disabled_background_image_

	// size_;
	// visible_area_;
	// parent_;
	// window_manager_;
	visibled_ = true;
	enabled_ = true;;
	need_update_ = true;
	// name_;

	// child_items_;
	// visibled_child_items_;
}

UIControl::~UIControl()
{
	visibled_child_items_.clear();
	child_items_.clear();
}

void UIControl::SetPresetPosition(const UIPresetPosition &preset_pos)
{
	if(preset_pos_ == preset_pos)
		return;
	preset_pos_ = preset_pos;
	SmartSetNeedUpdate(true);
}

bool UIControl::BuildControlFromXML(IUIBuilderInterface *ui_builder,
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{
	if(ui_builder == NULL || xml_document == NULL)
		return false;

	UIXmlAttribute attribute = NULL;
	attribute = xml_document->FirstAttribute(node, "class");
	if(attribute != NULL)
	{
		tstring class_value = auto_cvt(xml_document->AttributeValue(attribute)).c_tstr();
		str_trim(class_value, NULL);
		tstrings sub_strs = str_split(class_value, _T(':'));
		if(sub_strs.size() < 2)
		{
			TraceVE(_T("bad config for class %s"), auto_cvt(xml_document->AttributeName(attribute)).c_tstr());
			return false;
		}
		tstring xml_file = sub_strs[0];
		xml_file += _T(".xml");
		scoped_ref_ptr<IUIXMLDocumentInterface> cls_xml_doc;
		if(!ui_builder->LoadXml(xml_file.c_str(), cls_xml_doc) || cls_xml_doc == NULL)
		{
			TraceVE(_T("failed to load file %s"), xml_file.c_str());
			return false;
		}

		UIXmlNode cls_node = cls_xml_doc->FirstNode(auto_cvt(sub_strs[1].c_str()).c_utf8str());
		if(cls_node == NULL)
		{
			TraceVE(_T("XML file %s : missing node %s"), xml_file.c_str(), sub_strs[1].c_str());
			return false;
		}
		cls_xml_doc->NodeName(cls_node, xml_document->NodeName(node));

		if(!BuildControlFromXML(ui_builder, cls_xml_doc, cls_node))
		{
			return false;
		}

		if(!ApplyAttributes(ui_builder, xml_document, node))
			return false;

		if(!RebuildChilds(ui_builder, xml_document, node))
			return false;
		AfterBuild(ui_builder, xml_document, node);
		return true;
	}

	if(!ApplyAttributes(ui_builder, xml_document, node))
		return false;
	if(!BuildChilds(ui_builder, xml_document, node))
		return false;
	AfterBuild(ui_builder, xml_document, node);

	return true;
}

UIPresetPosition UIControl::GetPresetPosition()
{
	return preset_pos_;
}

void UIControl::SetAutoWidthBy(UIAutoSizeBy by)
{
	auto_width_by_ = by;
}

void UIControl::SetAutoHeightBy(UIAutoSizeBy by)
{
	auto_height_by_ = by;
}

HCURSOR UIControl::GetCursor()
{
	return NULL;
}

void UIControl::SetPresetHorzLayoutPositionType(UIPresetLayoutPositionType type)
{
	h_preset_layout_type_ = type;
	SetNeedUpdate(true);
}

UIPresetLayoutPositionType UIControl::GetPresetHorzLayoutPositionType() const
{
	return h_preset_layout_type_;
}

void UIControl::SetPresetVertLayoutPositionType(UIPresetLayoutPositionType type)
{
	v_preset_layout_type_ = type;
	SetNeedUpdate(true);
}

UIPresetLayoutPositionType UIControl::GetPresetVertLayoutPositionType() const
{
	return v_preset_layout_type_;
}

void UIControl::SetClientBorder(const UIRect &border_values)
{
	client_borders_ = border_values;
	SetNeedUpdate(true);
}

UIRect UIControl::GetClientBorder()
{
	return client_borders_;
}

void UIControl::SetPosition(const UIRect &pos, const UIRect &parent_visible_rt)
{
	need_update_ = false;
	if(pos_.Width() != pos.Width() || pos_.Height() != pos.Height())
	{
		pos_ = pos;
		OnSizeChanged();
	}else
	{
		pos_ = pos;
		OnRecalcChildsLayoutOnSizeChange();
	}

	UIRect visible_view_rt_on_my(UIControl_GetVisibleArea(parent_visible_rt, pos_));
	visible_view_rt_on_my.Translate(-pos_.left, -pos_.top);
	SetVisibleViewArea(visible_view_rt_on_my);
}

UIRect UIControl::GetPosition()
{
	return pos_;
}

int UIControl::GetWidth()
{
	if(!preset_pos_.HasWidth())
		return 0;
	if(!preset_pos_.IsAutoWidth())
		return preset_pos_.Width();
	return GetObjectAutoWidth();
}

int UIControl::GetHeight()
{
	if(!preset_pos_.HasHeight())
		return 0;
	if(!preset_pos_.IsAutoHeight())
		return preset_pos_.Height();
	return GetObjectAutoHeight();
}

bool UIControl::SetVisibleViewArea(const UIRect &visible_area)
{
#ifdef _DEBUG
	UIRect pos_in_my(pos_);
	pos_in_my.Translate(-pos_.left, -pos_.top);
	SS_ASSERT(pos_in_my.Contained(visible_area));
#endif
	if(!visible_area_.Equal(visible_area))
	{
		visible_area_ = visible_area;
		OnVisibleSizeChanged();
	}else
	{
		OnRecalcChildsLayoutOnVisibleSizeChanged();
	}
	return true;
}

UIRect UIControl::GetVisibleViewAreaInParentClient()
{
	UIRect ret(visible_area_);
	ret.Translate(pos_.left, pos_.top);
	return ret;
}

UIRect UIControl::GetVisibleViewAreaInMyPosition()
{
	return visible_area_;
}


UISize UIControl::GetClientSize()
{
	return UISize(pos_.Width() - client_borders_.left - client_borders_.right,
		pos_.Height() - client_borders_.top - client_borders_.bottom);
}

bool UIControl::ChildsPositionHasRelation()
{
	if(childs_position_has_relation_)
		return true;
	if(GetPresetPosition().IsAutoWidth() || GetPresetPosition().IsAutoHeight())
		return true;
	return false;
}

UIRect UIControl::GetVisibleClientViewAreaInParentClient()
{
	UIRect ret(pos_.left + client_borders_.left, pos_.top + client_borders_.top,
		pos_.right - client_borders_.right, pos_.bottom - client_borders_.bottom);
	ret = UIControl_GetVisibleArea(GetVisibleViewAreaInParentClient(), ret);
	return ret;
}

UIRect UIControl::GetVisibleViewAreaInMyClient()
{
	UIRect rt = GetVisibleViewAreaInParentClient();
	rt.Translate(-pos_.left-client_borders_.left, -pos_.top-client_borders_.top);
	return rt;
}

UIRect UIControl::GetVisibleClientViewAreaInMyClient()
{
	UIRect rt = GetVisibleClientViewAreaInParentClient();
	rt.Translate(-pos_.left-client_borders_.left, -pos_.top-client_borders_.top);
	return rt;
}

UIPoint UIControl::GetLeftTopPointOnClient()
{
	UIPoint ret;
	ret.x = pos_.left;
	ret.y = pos_.top;

	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent != NULL)
	{
		UIPoint parent_lt = parent->GetLeftTopPointOnClient();
		UIRect client_borders = parent->GetClientBorder();

		ret.x += client_borders.left;
		ret.x += parent_lt.x;
		ret.y += client_borders.top;
		ret.y += parent_lt.y;
		return ret;
	}

	return ret;
}

UIRect UIControl::GetPositionOnClient()
{
	UIRect rt = GetPosition();
	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent != NULL)
	{
		UIPoint pt = parent->GetLeftTopPointOnClient();
		rt.Translate(pt.x + parent->GetClientBorder().left, pt.y + parent->GetClientBorder().top);
	}
	return rt;
}

UIRect UIControl::GetVisiblePositionOnClient()
{
	UIRect rt = GetVisibleViewAreaInParentClient();
	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent != NULL)
	{
		UIPoint pt = parent->GetLeftTopPointOnClient();
		rt.Translate(pt.x + parent->GetClientBorder().left, pt.y + parent->GetClientBorder().top);
	}
	return rt;
}

UIRect UIControl::GetClientPositionOnClient()
{
	UIRect rt = GetPositionOnClient();
	rt.left += client_borders_.left;
	rt.top += client_borders_.top;
	rt.right -= client_borders_.right;
	rt.bottom -= client_borders_.bottom;
	return rt;
}

UIRect UIControl::GetVisibleClientPositionOnClient()
{
	UIRect rt = GetVisibleClientViewAreaInParentClient();
	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent != NULL)
	{
		UIPoint pt = parent->GetLeftTopPointOnClient();
		rt.Translate(pt.x + parent->GetClientBorder().left, pt.y + parent->GetClientBorder().top);
	}
	return rt;
}

UINT UIControl::GetProperties()
{
	return properties_;
}

void UIControl::SetTooltipInfo(const tstring &tooltip)
{
	tooltip_info_ = tooltip;
}

tstring UIControl::GetTooltipInfo()
{
	return tooltip_info_;
}

void UIControl::SetBackgroundTransparent(bool transparent)
{
	background_transparent_ = transparent;
}

void UIControl::SetBackgroundColor(unsigned long color)
{
	background_color_ = color;
}

void UIControl::SetDisabledBackgroundColor(unsigned long color)
{
	disabled_background_color_ = color;
}

void UIControl::SetBackgroundImage(const UIPresetImage &img)
{
	background_image_ = img;
}

void UIControl::SetDisabledBackgroundImage(const UIPresetImage &img)
{
	disabled_background_image_ = img;
}

void UIControl::SetShowBorder(bool show)
{
	show_border_ = show;
	SetNeedUpdate(true);
}

bool UIControl::IsShowBorder()
{
	return show_border_;
}

void UIControl::SetBorderColor(unsigned long color)
{
	border_color_ = color;
	SetNeedUpdate(true);
}

void UIControl::SetUserData(const tstring &name, void *user_data)
{
	user_data_[name] = user_data;
}

void* UIControl::GetUserData(const tstring &name) const
{
	tstring_void_map::const_iterator iter = user_data_.find(name);
	if(iter == user_data_.end())
		return NULL;
	return iter->second;
}

void UIControl::SetUserStringData(const tstring &name, const tstring &data)
{
	user_string_data_[name] = data;
}

tstring UIControl::GetUserStringData(const tstring &name)
{
	tstring_tstring_map::const_iterator iter = user_string_data_.find(name);
	if(iter == user_string_data_.end())
		return _T("");
	return iter->second;
}

scoped_ref_ptr<IUIControlInterface> UIControl::GetParent()
{
	return parent_.get();
}

bool UIControl::SetParent(IUIControlInterface *parent)
{
	if(parent == parent_.get())
		return true;

	scoped_ref_ptr<IUIManagerInterface> old_man = GetWindowManager();
	scoped_ref_ptr<IUIControlInterface> old = parent;
	if(parent == NULL)
		parent_.reset();
	else
		parent_ = parent->as_weak_ptr();
	
	scoped_ref_ptr<IUIManagerInterface> new_man = GetWindowManager();
	if(old_man != new_man)
	{
		NotifyWindowManagerChanged(old_man, new_man);
	}

	return true;
}

scoped_ref_ptr<IUIManagerInterface> UIControl::GetWindowManager()
{
	scoped_ref_ptr<IUIManagerInterface> ret = window_manager_.get();
	if(ret != NULL)
		return ret;
	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent == NULL)
		return NULL;
	return parent->GetWindowManager();
}

IUIControlInterfaceAutoPtrs UIControl::GetChilds()
{
	return child_items_;
}

scoped_ref_ptr<IUIControlInterface> UIControl::FindControl(FindControlCB cb, void *data, unsigned int flags)
{
	if(cb == NULL)
		return NULL;

	if(SS_FLAG_ISSET(flags, kUIFindVisibled) && !IsVisibled())
		return NULL;

	if(SS_FLAG_ISSET(flags, kUIFindEnabled) && !IsEnabled())
		return NULL;

	if(SS_FLAG_ISSET(flags, kUIFindHittest))
	{
		UIFindControlByPoint *find_ctr_d = static_cast<UIFindControlByPoint*>(data);
		if(find_ctr_d == NULL)
			return NULL;
		if(find_ctr_d->cancelled)
			return NULL;

		UIPoint clp = GetLeftTopPointOnClient();
		if(!::PtInRect(&GetVisiblePositionOnClient(), find_ctr_d->pt))
			return NULL;
	}

	if(SS_FLAG_ISSET(flags, kUIFindMeFirst))
	{
		scoped_ref_ptr<IUIControlInterface> ret = cb(this, data);
		if(ret != NULL)
			return ret;
	}

	IUIControlInterfaceAutoPtrs *childs = &child_items_;
	if(SS_FLAG_ISSET(flags, kUIFindOnlyVisibledChild))
		childs = &visibled_child_items_;
	IUIControlInterfaceAutoPtrs &child_items = *childs;

	if(SS_FLAG_ISSET(flags, kUIFindTopFirst))
	{
		for(IUIControlInterfaceAutoPtrs::reverse_iterator iter=child_items.rbegin();
			iter!=child_items.rend(); iter++)
		{
			scoped_ref_ptr<IUIControlInterface> ret = (*iter)->FindControl(cb, data, flags);
			if(ret != NULL)
				return ret;
		}
	}else
	{
		for(IUIControlInterfaceAutoPtrs::iterator iter=child_items.begin();
			iter!=child_items.end(); iter++)
		{
			scoped_ref_ptr<IUIControlInterface> ret = (*iter)->FindControl(cb, data, flags);
			if(ret != NULL)
				return ret;
		}
	}

	if(!SS_FLAG_ISSET(flags, kUIFindMeFirst))
	{
		scoped_ref_ptr<IUIControlInterface> ret = cb(this, data);
		if(ret != NULL)
			return ret;
	}

	return NULL;
}

scoped_ref_ptr<IUIControlInterface> UIControl::FindControl(const tstring &name)
{
	UIFindControlByName find_data;
	find_data.name = name;
	return FindControl(__FindControlForFindByName, &find_data, kUIFindAll);
}

scoped_ref_ptr<IUIControlInterface> UIControl::FindNearstControl(const tstring &name)
{
	scoped_ref_ptr<IUIControlInterface> ret;
	scoped_ref_ptr<IUIControlInterface> b_control = this;
	while(b_control != NULL && ret == NULL)
	{
		ret = b_control->FindControl(name);
		b_control = b_control->GetParent();
	}
	return ret;
}

scoped_ref_ptr<IUIControlInterface> UIControl::FindControl(const UIFindControlByPoint &find_data)
{
	return FindControl(__FindControlForFindByHittest, (void*)&find_data,
		kUIFindVisibled|kUIFindHittest|kUIFindOnlyVisibledChild|kUIFindTopFirst);
}

bool UIControl::IsControlExists(IUIControlInterface *control)
{
	if(control == NULL)
		return false;
	return control->compare(FindControl(__FindControlForControlExists, (void*)control,
		kUIFindAll).get());
}

bool UIControl::DoAnimation(IUIControlInternalAnimationInterface *animation)
{
	if(animation == NULL)
		return false;
	CsLockGuard(internal_animations_lock_);
	IUIControlInternalAnimationInterfaceAutoPtrs::iterator iter = std::find(internal_animations_.begin(),
		internal_animations_.end(), animation);
	SS_ASSERT(iter == internal_animations_.end());
	internal_animations_.push_back(animation);
	SS_VERIFY(animation->StartAnimate(this));
	return true;
}

void UIControl::SetName(const tstring &name)
{
	name_ = name;
}

tstring UIControl::GetName()
{
	return name_;
}

void UIControl::SetVisible(bool visible)
{
	if(visibled_ != visible)
	{
		visibled_ = visible;
		SmartSetNeedUpdate(true);
	}
}

bool UIControl::IsVisibled()
{
	if(!visibled_)
		return false;
	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent == NULL)
		return true;
	return parent->IsVisibled();
}

void UIControl::SetEnable(bool enable)
{
	if(enabled_ != enable)
	{
		enabled_ = enable;
		SmartSetNeedUpdate(true);
	}
}

bool UIControl::IsEnabled()
{
	if(!enabled_)
		return false;
	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent == NULL)
		return true;
	return parent->IsEnabled();
}

void UIControl::DoAction()
{

}

bool UIControl::AddChild(IUIControlInterface *control)
{
	if(control == NULL)
		return false;
	child_items_.push_back(control);
	control->SetParent(this);
	SmartSetNeedUpdate(true);
	return true;
}

bool UIControl::RemoveChild(IUIControlInterface *control)
{
	IUIControlInterfaceAutoPtrs::iterator iter = std::find(child_items_.begin(), child_items_.end(), control);
	if(iter == child_items_.end())
		return false;

	(*iter)->SetParent(NULL);
	child_items_.erase(iter);
	SmartSetNeedUpdate(true);

	return true;
}

scoped_ref_ptr<IUIManagerInterface> UIControl::SetDirectUIManager(IUIManagerInterface *ui_manager)
{
	if(ui_manager == window_manager_.get())
		return window_manager_.get();

	scoped_ref_ptr<IUIManagerInterface> ret = window_manager_.get();
	window_manager_.reset();
	if(ui_manager != NULL)
		window_manager_ = ui_manager->as_weak_ptr();
	NotifyWindowManagerChanged(ret, window_manager_.get());
	return ret;
}

scoped_ref_ptr<IUIManagerInterface> UIControl::GetDirectUIManager() const
{
	return window_manager_.get();
}

void UIControl::SetNeedUpdate(bool need)
{
	need_update_ = need;
	scoped_ref_ptr<IUIManagerInterface> ui_man = GetWindowManager();
	if(ui_man != NULL)
	{
		UIRect invalidte_rt = ui_man->RecalcLayout();
		ui_man->Invalidate(&invalidte_rt);
	}
}

void UIControl::LayoutChilds()
{
	need_update_ = false;
	OnRecalcChildsLayoutOnSizeChange();
	OnRecalcChildsLayoutOnVisibleSizeChanged();
}

void UIControl::SmartSetNeedUpdate(bool need)
{
	if(parent_ == NULL)
	{
		SetNeedUpdate(need);
		return;
	}

	if(!parent_->ChildsPositionHasRelation())
	{
		SetNeedUpdate(need);
		return;
	}

	if(!GetPresetPosition().IsAutoWidth() && !GetPresetPosition().IsAutoHeight())
	{
		SetNeedUpdate(need);
		return;
	}

	scoped_ref_ptr<IUIControlInterface> parent = GetParent();
	if(parent.get())
	{
		need_update_ = true;
		parent->SmartSetNeedUpdate(need);
	}else
	{
		SetNeedUpdate(need);
	}
}

bool UIControl::NeedUpdate()
{
	return need_update_;
}

void UIControl::Invalidate()
{
	scoped_ref_ptr<IUIManagerInterface> win_man = GetWindowManager();
	if(win_man == NULL)
		return;
	win_man->Invalidate(&GetPositionOnClient());
}

bool UIControl::SendNotify(UINotify &notify)
{
	scoped_ref_ptr<IUIManagerInterface> win_man = GetWindowManager();
	if(win_man == NULL)
		return false;
	win_man->SendNotify(notify);
	return true;
}

void UIControl::DispatchEventOfControl(UIEvent &evt)
{
	scoped_ref_ptr<IUIEventReceiverInterface> evt_receiver = dynamic_cast<IUIEventReceiverInterface*>(this);
	if(evt_receiver == NULL)
		return;
	evt_receiver->DispatchEvent(evt);
}

void UIControl::Render(void* dc, const UIRect &clip_rc)
{
	if(!IsVisibled())
		return;
	if(visible_area_.IsEmptry())
		return;

	UIRenderContext rc;
	rc.visible_pos_on_client = GetVisiblePositionOnClient();

	UIRect clip;
	clip.IntersectRect(clip_rc, rc.visible_pos_on_client);
	if(clip.IsEmptry())
		return;

	rc.wm = GetWindowManager();
	if(rc.wm == NULL)
		return;
	rc.rr = rc.wm->GetResourceRener();
	if(rc.rr == NULL)
		return;

	rc.dc = dc;
	rc.clip_rt = clip;
	rc.pos_on_client = GetPositionOnClient();
	rc.client_pos_on_client = GetClientPositionOnClient();
	rc.visible_client_pos_on_client = GetVisibleClientPositionOnClient();

	OnRenderBeforeBackground(rc);
	OnRenderBackgroundColor(rc);
	OnRenderBackgroundImage(rc);
	OnRenderAfterBackground(rc);
	OnRenderForeground(rc);

	{
		UIRect clip_childs;
		clip_childs.IntersectRect(clip_rc, GetVisibleClientPositionOnClient());
		rc.clip_rt = clip_childs;
		OnRenderChilds(rc);
	}

	rc.clip_rt = clip;
	OnRenderBorder(rc);
}

void UIControl::OnWindowManagerChangedCB(IUIManagerInterface *old_manager, IUIManagerInterface *new_manager)
{
	if(old_manager != NULL)
	{
		KillTimerOnWindowManager();
	}

	if(new_manager != NULL)
	{
		CsLockGuard(timer_infos_lock_);
		if(timer_infos_.size() > 0)
			TrySetTimerOnWindowManager();
	}
}

void UIControl::OnStateChangedCB()
{
	if(OnStateChanged)
	{
		OnStateChanged((IUIControlInterface*)this);
	}
}

int UIControl::GetObjectAutoWidth()
{
	return GetControlAutoWidth();
}

int UIControl::GetObjectAutoHeight()
{
	return GetControlAutoHeight();
}

void UIControl::OnTimerCB(unsigned int timer_id)
{
	if(OnTimerInternalCB(timer_id))
		return;
	OnTimerCommonCB(timer_id);
}

void UIControl::TrySetTimerOnWindowManager()
{
	scoped_ref_ptr<IUIManagerInterface> win_man = GetWindowManager();
	if(win_man != NULL)
	{
		win_man->SetTimer(this);
	}
}

void UIControl::KillTimerOnWindowManager()
{
	scoped_ref_ptr<IUIManagerInterface> win_man = GetWindowManager();
	if(win_man != NULL)
	{
		win_man->KillTimer(this);
	}
}

void UIControl::DispatchEvent(UIEvent &evt)
{
	if(OnEvent)
	{
		OnEvent(&evt);
	}
	DoEvent(evt);
}

void UIControl::DoEvent(UIEvent &evt)
{
	if(evt.type == kEvtSetCursor)
	{
		HCURSOR cursor = GetCursor();
		if(cursor != NULL)
		{
			::SetCursor(cursor);
			evt.lret = TRUE;
			return;
		}
	}
}

void UIControl::OnRenderBeforeBackground(const UIRenderContext &rc)
{

}

void UIControl::OnRenderBackgroundColor(const UIRenderContext &rc)
{
	if(background_transparent_)
		return;
	rc.rr->DrawColor(rc.dc, rc.visible_pos_on_client, GetBackgroundColor());
}

void UIControl::OnRenderBackgroundImage(const UIRenderContext &rc)
{
	UIPresetImage& img = GetBackgroundImage();
	if(img.image_name.empty())
		return;

	UIPresetImageInfo img_info;
	if(!rc.rr->CheckPresetImageInfo(img, img_info))
		return;

	UIRect rt_src = img.image_src_rect;
	if(rt_src.Width() <= 0)
	{
		rt_src.left = 0;
		rt_src.right = img_info.cx;
	}
	if(rt_src.Height() <= 0)
	{
		rt_src.top = 0;
		rt_src.bottom = img_info.cy;
	}
	rc.rr->DrawImage(rc.dc, img.image_name, &rt_src,
		rc.pos_on_client, &img.image_zoom_guardlines);
}

void UIControl::OnRenderAfterBackground(const UIRenderContext &rc)
{

}

void UIControl::OnRenderForeground(const UIRenderContext &rc)
{
	if(background_transparent_)
		return;

	DWORD a = 0;
	DWORD rgb = DWORDStripAlpha(GetBackgroundColor(), a);
	DWORD hsl = RGBToHSL(rgb);
	hsl = HSLAdd(hsl, 0, 0, 50);
	rgb = HSLToRGB(hsl);

	rc.rr->DrawColor(rc.dc, rc.visible_client_pos_on_client, DWORDRGB2ARGB(rgb, 88));
}

void UIControl::OnRenderChilds(const UIRenderContext &rc)
{
	for(IUIControlInterfaceAutoPtrs::iterator iter=visibled_child_items_.begin();
		iter!=visibled_child_items_.end(); iter++)
	{
		(*iter)->Render(rc.dc, rc.clip_rt);
	}
}

void UIControl::OnRenderBorder(const UIRenderContext &rc)
{
	if(!show_border_)
		return;
	rc.rr->DrawFrame(rc.dc, rc.pos_on_client, border_color_);
}

bool UIControl::ApplyAttributes(IUIBuilderInterface *ui_builder, 
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{
	if(ui_builder == NULL || xml_document == NULL)
		return false;

	UIXmlAttribute attribute = NULL;

	//
	attribute = xml_document->FirstAttribute(node, "name");
	if(attribute != NULL)
	{
		SetName(auto_cvt(xml_document->AttributeValue(attribute)).c_tstr());
	}

	// 
	UIPresetPosition preset_pos = GetPresetPosition();

	attribute = xml_document->FirstAttribute(node, "left");
	if(attribute != NULL)
	{
		int n = 0;
		bool b = true;
		if(UIValueParseUtil::ParseIntBool(xml_document->AttributeValue(attribute), n, b) >= 1)
		{
			preset_pos.SetLeft(n, b);
		}
	}

	attribute = xml_document->FirstAttribute(node, "top");
	if(attribute != NULL)
	{
		int n = 0;
		bool b = true;
		if(UIValueParseUtil::ParseIntBool(xml_document->AttributeValue(attribute), n, b) >= 1)
		{
			preset_pos.SetTop(n, b);
		}
	}

	attribute = xml_document->FirstAttribute(node, "right");
	if(attribute != NULL)
	{
		int n = 0;
		bool b = true;
		if(UIValueParseUtil::ParseIntBool(xml_document->AttributeValue(attribute), n, b) >= 1)
		{
			preset_pos.SetRight(n, b);
		}
	}

	attribute = xml_document->FirstAttribute(node, "bottom");
	if(attribute != NULL)
	{
		int n = 0;
		bool b = true;
		if(UIValueParseUtil::ParseIntBool(xml_document->AttributeValue(attribute), n, b) >= 1)
		{
			preset_pos.SetBottom(n, b);
		}
	}

	attribute = xml_document->FirstAttribute(node, "width");
	if(attribute != NULL)
	{
		int n = 0;
		if(UIValueParseUtil::ParseInt(xml_document->AttributeValue(attribute), n) == 1)
		{
			preset_pos.SetWidth(n);
		}
	}

	attribute = xml_document->FirstAttribute(node, "height");
	if(attribute != NULL)
	{
		int n = 0;
		if(UIValueParseUtil::ParseInt(xml_document->AttributeValue(attribute), n) == 1)
		{
			preset_pos.SetHeight(n);
		}
	}

	SetPresetPosition(preset_pos);

	attribute = xml_document->FirstAttribute(node, "auto_width_by");
	if(attribute != NULL)
	{
		int n = 0;
		if(strstr(xml_document->AttributeValue(attribute), "by_background"))
		{
			SetAutoWidthBy(kASByBackground);
		}else if(strstr(xml_document->AttributeValue(attribute), "by_childs"))
		{
			SetAutoWidthBy(kASByChilds);
		}else
		{
			SetAutoWidthBy(kASByAuto);
		}
	}

	attribute = xml_document->FirstAttribute(node, "auto_height_by");
	if(attribute != NULL)
	{
		int n = 0;
		if(strstr(xml_document->AttributeValue(attribute), "by_background"))
		{
			SetAutoHeightBy(kASByBackground);
		}else if(strstr(xml_document->AttributeValue(attribute), "by_childs"))
		{
			SetAutoHeightBy(kASByChilds);
		}else
		{
			SetAutoHeightBy(kASByAuto);
		}
	}

	//
	attribute = xml_document->FirstAttribute(node, "v_layout_pos_type");
	if(attribute != NULL)
	{
		UIPresetLayoutPositionType lptype = GetPresetVertLayoutPositionType();

		const char *val = xml_document->AttributeValue(attribute);
		if(strstr(val, "near") != NULL)
			lptype = kLPNear;
		else if(strstr(val, "center") != NULL)
			lptype = kLPCenter;
		else if(strstr(val, "far") != NULL)
			lptype = kLPFar;
		else if(strstr(val, "free") != NULL)
			lptype = kLPFree;
		else if(strstr(val, "expand") != NULL)
			lptype = kLPExpand;

		SetPresetVertLayoutPositionType(lptype);
	}

	attribute = xml_document->FirstAttribute(node, "h_layout_pos_type");
	if(attribute != NULL)
	{
		UIPresetLayoutPositionType lptype = GetPresetHorzLayoutPositionType();

		const char *val = xml_document->AttributeValue(attribute);
		if(strstr(val, "near") != NULL)
			lptype = kLPNear;
		else if(strstr(val, "center") != NULL)
			lptype = kLPCenter;
		else if(strstr(val, "far") != NULL)
			lptype = kLPFar;
		else if(strstr(val, "free") != NULL)
			lptype = kLPFree;
		else if(strstr(val, "expand") != NULL)
			lptype = kLPExpand;

		SetPresetHorzLayoutPositionType(lptype);
	}

	//
	attribute = xml_document->FirstAttribute(node, "client_border");
	if(attribute != NULL)
	{
		UIRect r;
		if(UIValueParseUtil::ParseRect(xml_document->AttributeValue(attribute), r) == 1)
		{
			SetClientBorder(r);
		}
	}

	//
	attribute = xml_document->FirstAttribute(node, "background_transparent");
	if(attribute != NULL)
	{
		bool b = true;
		if(UIValueParseUtil::ParseBool(xml_document->AttributeValue(attribute), b) == 1)
		{
			SetBackgroundTransparent(b);
		}
	}

	attribute = xml_document->FirstAttribute(node, "background_color");
	if(attribute != NULL)
	{
		unsigned long c = 0;
		if(UIValueParseUtil::ParseColor(xml_document->AttributeValue(attribute), c) == 1)
		{
			SetBackgroundColor(c);
		}
	}

	attribute = xml_document->FirstAttribute(node, "disabled_background_color");
	if(attribute != NULL)
	{
		unsigned long c = 0;
		if(UIValueParseUtil::ParseColor(xml_document->AttributeValue(attribute), c) == 1)
		{
			SetDisabledBackgroundColor(c);
		}
	}

	//
	attribute = xml_document->FirstAttribute(node, "background_image");
	if(attribute != NULL)
	{
		UIPresetImage i;
		if(UIValueParseUtil::ParseImage(xml_document->AttributeValue(attribute), i) == 1)
		{
			SetBackgroundImage(i);
		}
	}

	attribute = xml_document->FirstAttribute(node, "disabled_background_image");
	if(attribute != NULL)
	{
		UIPresetImage i;
		if(UIValueParseUtil::ParseImage(xml_document->AttributeValue(attribute), i) == 1)
		{
			SetDisabledBackgroundImage(i);
		}
	}

	//
	attribute = xml_document->FirstAttribute(node, "show_border");
	if(attribute != NULL)
	{
		bool b = false;
		if(UIValueParseUtil::ParseBool(xml_document->AttributeValue(attribute), b) == 1)
		{
			SetShowBorder(b);
		}
	}

	attribute = xml_document->FirstAttribute(node, "border_color");
	if(attribute != NULL)
	{
		unsigned long c = 0;
		if(UIValueParseUtil::ParseColor(xml_document->AttributeValue(attribute), c) == 1)
		{
			SetBorderColor(c);
		}
	}

	//
	attribute = xml_document->FirstAttribute(node, "visible");
	if(attribute != NULL)
	{
		bool b = true;
		if(UIValueParseUtil::ParseBool(xml_document->AttributeValue(attribute), b) == 1)
		{
			SetVisible(b);
		}
	}

	attribute = xml_document->FirstAttribute(node, "enable");
	if(attribute != NULL)
	{
		bool b = true;
		if(UIValueParseUtil::ParseBool(xml_document->AttributeValue(attribute), b) == 1)
		{
			SetEnable(b);
		}
	}

	//
	// name|value;name|value;name|value
	attribute = xml_document->FirstAttribute(node, "user_string_datas");
	if(attribute != NULL)
	{
		tchar delimiter = _T('|');
		tstrings pairs = str_split(auto_cvt(xml_document->AttributeValue(attribute)).c_tstr(),
			_T(';'));
		for(tstrings::iterator iter=pairs.begin(); iter!=pairs.end(); iter++)
		{
			tstrings pr = str_split((*iter), delimiter);
			if(pr.size() != 2)
			{
				if(pr.size() == 1 && iter == pairs.begin())
				{
					if(pr[0].length() == 3 && pr[0][0] == _T('[') && pr[0][2] == _T(']'))
					{
						delimiter = pr[0][1];
					}
				}
				continue;
			}
			tstring name = pr[0];
			str_trim(name, NULL);
			if(name.empty())
				continue;
			tstring val = pr[1];
			str_trim(val, NULL);
			SetUserStringData(name.c_str(), val);
		}
	}

	return true;
}

bool UIControl::BuildChilds(IUIBuilderInterface *ui_builder,
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{
	if(ui_builder == NULL || xml_document == NULL)
		return false;

	for (UIXmlNode child_node = xml_document->FirstNode(node, NULL); child_node != NULL;
		child_node = xml_document->NextSiblingNode(child_node, NULL))
	{
		scoped_ref_ptr<IUIControlInterface> child;
		if(ui_builder->BuildControl(xml_document, child_node, child) || child != NULL)
		{
			if(!AddChild(child))
			{
				TraceVE(_T("build chid success from xml node %s, but failed add to the parent"),
					auto_cvt(xml_document->NodeName(child_node)).c_tstr());
			}
		}else
		{
			TraceVE(_T("build chid failed from xml node %s"), auto_cvt(xml_document->NodeName(child_node)).c_tstr());
		}
	}
	return true;
}

bool UIControl::RebuildChilds(IUIBuilderInterface *ui_builder,
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{
	if(ui_builder == NULL || xml_document == NULL)
		return false;

	for (UIXmlNode child_node = xml_document->FirstNode(node, NULL); child_node != NULL;
		child_node = xml_document->NextSiblingNode(child_node, NULL))
	{
		UIXmlAttribute attirbute = xml_document->FirstAttribute(child_node, "name");
		if(attirbute == NULL)
			continue;
		scoped_ref_ptr<IUIControlInterface> child = FindControl(auto_cvt(xml_document->AttributeValue(attirbute)).c_tstr());
		if(child == NULL)
			continue;

		UIControl* bc_child = dynamic_cast<UIControl*>(child.get());
		if(!bc_child->ApplyAttributes(ui_builder, xml_document, child_node))
		{
			TraceVE(_T("apply attributes failed. name=%s"),
				auto_cvt(xml_document->AttributeValue(attirbute)).c_tstr());
			continue;
		}
		bc_child->AfterBuild(ui_builder, xml_document, child_node);
	}
	return true;
}

void UIControl::AfterBuild(IUIBuilderInterface *ui_builder,
	IUIXMLDocumentInterface *xml_document, UIXmlNode node)
{

}

int UIControl::GetControlAutoWidth()
{
	if(auto_width_by_ == kASByAuto || auto_width_by_ == kASByBackground)
		return CheckPreseImageSize(GetBackgroundImage()).cx;
	return GetChildsRect().Width();
}

int UIControl::GetControlAutoHeight()
{
	if(auto_width_by_ == kASByAuto || auto_width_by_ == kASByBackground)
		return CheckPreseImageSize(GetBackgroundImage()).cy;
	return GetChildsRect().Height();
}

unsigned long UIControl::GetBackgroundColor()
{
	if(IsEnabled())
		return background_color_;
	return disabled_background_color_;
}

UIPresetImage& UIControl::GetBackgroundImage()
{
	if(IsEnabled())
		return background_image_;
	return disabled_background_image_;
}

void UIControl::NotifyWindowManagerChanged(
	IUIManagerInterface *old_man,
	IUIManagerInterface *new_man
	)
{
	OnWindowManagerChangedCB(old_man, new_man);
	NotifyChildsWindowManagerChanged(old_man, new_man);
}

void UIControl::NotifyChildsWindowManagerChanged(
	IUIManagerInterface *old_man,
	IUIManagerInterface *new_man
	)
{
	for(IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin(); iter!=child_items_.end(); iter++)
	{
		(*iter)->OnWindowManagerChangedCB(old_man, new_man);
	}
}

UISize UIControl::CheckPreseImageSize(const UIPresetImage &preset_img)
{
	scoped_ref_ptr<IUIManagerInterface> win_man = GetWindowManager();
	if(win_man == NULL)
		return UISize();
	scoped_ref_ptr<IUIResourceRenderInterface> rr = win_man->GetResourceRener();
	if(rr == NULL)
		return UISize();

	UIPresetImageInfo iinfo;
	if(!rr->CheckPresetImageInfo(preset_img, iinfo))
		return UISize();

	return UISize((int)iinfo.cx, (int)iinfo.cy);
}

UIRect UIControl::GetChildsRect()
{
	UIRect rt;

	for(IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin(); iter!=child_items_.end(); iter++)
	{
		IUIControlInterface *child = *iter;
		if(child == NULL)
			continue;

		UIRect rt_calced;
		if(!child->GetPresetPosition().GetPosition(0, 0, rt_calced, dynamic_cast<IUIAutoSizeInterface*>(child)))
			continue;
		rt.UnionRect(rt, rt_calced);
	}
	rt.Inflate(client_borders_);
	rt.left = 0;
	rt.top = 0;
	return rt;
}

void UIControl::OnSizeChanged()
{
	OnRecalcChildsLayoutOnSizeChange();
}

void UIControl::OnVisibleSizeChanged()
{
	OnRecalcChildsLayoutOnVisibleSizeChanged();
}

void UIControl::OnRecalcChildsLayoutOnSizeChange()
{

}

void UIControl::OnRecalcChildsLayoutOnVisibleSizeChanged()
{
	visibled_child_items_.clear();
	if(visible_area_.Width() <= 0 || visible_area_.Height() <= 0)
	{
		return;
	}

	for(IUIControlInterfaceAutoPtrs::iterator iter=child_items_.begin(); iter!=child_items_.end(); iter++)
	{
		IUIControlInterfaceAutoPtr &child = (*iter);
		SS_ASSERT(child.get() != NULL);
		UIControl_SetPostion(GetClientSize(), GetVisibleClientViewAreaInMyClient(), child);
		if(child->GetVisibleViewAreaInMyPosition().Width() > 0 && child->GetVisibleViewAreaInMyPosition().Height() > 0)
			visibled_child_items_.push_back(child);
	}
}

bool UIControl::OnTimerInternalCB(unsigned int timer_id)
{
	for(IUIControlInternalAnimationInterfaceAutoPtrs::iterator iter=internal_animations_.begin();
		iter!=internal_animations_.end(); iter++)
	{
		if((*iter)->GetTimerID() == timer_id)
		{
			UIStepResult ar = (*iter)->DoAnimationStep();
			if(ar != kASContinue)
			{
				(*iter)->StopAnimation();
				internal_animations_.erase(iter);
			}
			return true;
		}
	}

	return false;
}

void UIControl::OnTimerCommonCB(unsigned int timer_id)
{

}

scoped_ref_ptr<IUIControlInterface> UIControl::__FindControlForFindByName(IUIControlInterface *control, void *data)
{
	UIFindControlByName *find_struct = static_cast<UIFindControlByName*>(data);
	if(find_struct == NULL)
		return NULL;
	if(!find_struct->name.empty())
	{
		if(control->GetName() != find_struct->name)
			return NULL;
	}
	return control;
}

scoped_ref_ptr<IUIControlInterface> UIControl::__FindControlForFindByHittest(IUIControlInterface *control, void *data)
{
	if(control == NULL)
		return NULL;

	UIFindControlByPoint *find_data = static_cast<UIFindControlByPoint*>(data);
	if(find_data == NULL || find_data->cancelled)
		return NULL;

	if(!::PtInRect(&control->GetVisiblePositionOnClient(), find_data->pt))
		return NULL;

	if(find_data->for_cursor)
	{
		if(control->GetCursor() == NULL)
			return NULL;
	}

	if(find_data->for_tooltip)
	{
		tstring ttinfo = control->GetTooltipInfo();
		if(ttinfo.empty())
			return NULL;
	}

	if(find_data->NeedHittestProperty())
	{
		if(!SS_FLAG_ISSET(control->GetProperties(), kControlPropertyHittest))
			return NULL;
	}

	find_data->cancelled = true;

	UIFocusableControl *focusble_control = dynamic_cast<UIFocusableControl*>(control);

	if(find_data->for_over)
	{
		if(focusble_control == NULL || !focusble_control->IsOverSensitive())
			return NULL;
	}

	if(find_data->for_press)
	{
		if(focusble_control == NULL || !focusble_control->IsPressSensitive())
			return NULL;
	}

	if(find_data->for_focus)
	{
		if(focusble_control == NULL || !focusble_control->IsFocusSensitive())
			return NULL;
	}

	return control;
}

scoped_ref_ptr<IUIControlInterface> UIControl::__FindControlForControlExists(
	IUIControlInterface *control, void *data)
{
	IUIControlInterface *compare_ptr = (IUIControlInterface*)data;
	if(compare_ptr == NULL)
		return NULL;
	if(!compare_ptr->compare(control))
		return NULL;
	return control;
}
_SSUIL_END
_SSL_END
